/*
 * 转换时间
 * CustomDateFtt(1565059668200,"yyyy-MM-dd hh:mm:ss") => '2019-08-06 10:47:48'
 * CustomDateFtt(1565059668200,"yyyy-MM-dd") => '2019-08-06'
 */
function CustomDateFtt(date, fmt) {
  if (date != null && date != '' && date != undefined) {
    if (typeof date == 'string') {
      date = date.replace(/-/g, '/');
    }
    var date = new Date(date);
    var o = {
      'M+': date.getMonth() + 1,
      'd+': date.getDate(),
      'h+': date.getHours(),
      'm+': date.getMinutes(),
      's+': date.getSeconds(),
      'q+': Math.floor((date.getMonth() + 3) / 3), //季度
      S: date.getMilliseconds(), //毫秒
    };
    o.S < 100 && (o.S = o.S < 10 ? '00' + o.S : '0' + o.S);
    if (/(y+)/.test(fmt))
      fmt = fmt.replace(
        RegExp.$1,
        (date.getFullYear() + '').substr(4 - RegExp.$1.length)
      );
    for (var k in o)
      if (new RegExp('(' + k + ')').test(fmt))
        fmt = fmt.replace(
          RegExp.$1,
          RegExp.$1.length == 1
            ? o[k]
            : ('00' + o[k]).substr(('' + o[k]).length)
        );
  } else {
    fmt = '';
  }
  return fmt;
}

// numberFormat (千分位)分隔符
function numberFormat(num) {
  if (isNaN(parseFloat(num)) || parseFloat(num) === Infinity) return '';
  let fixedIndex =
    num.toString().indexOf('.') === -1
      ? 0
      : num.toString().split('.')[1].length;
  return parseFloat(num)
    .toFixed(fixedIndex)
    .replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,');
}

// NumberToFixed 四舍五入
// 注：js自带的toFixed有银行家算法缺陷，故重写 例：toFixed(1.255, 2)
function NumberToFixed(num, digits = 0) {
  if (isNaN(parseFloat(num)) || parseFloat(num) === Infinity) return '';
  let zeroStrNum = num.toString();

  // 处理科学计算情况
  if (zeroStrNum.includes('e')) {
    const m = zeroStrNum.match(/\d(?:\.(\d*))?e([+-]\d+)/);
    zeroStrNum = num.toFixed(Math.max(0, (m[1] || '').length - m[2]));
  }

  let isNegativeNum = false;
  // 判断是否为负数
  if (zeroStrNum.startsWith('-')) {
    isNegativeNum = true;
    zeroStrNum = zeroStrNum.slice(1);
  }
  // 获取小数点位置
  const dotIndex = zeroStrNum.indexOf('.');
  // 如果是整数/保留小数位数等于超过当前小数长度，则直接用toFixed返回
  if (dotIndex === -1 || zeroStrNum.length - (dotIndex + 1) <= digits) {
    return num.toFixed(digits);
  }

  // 找到需要进行四舍五入的部分
  let numArr = zeroStrNum.match(/\d/g) || [];
  numArr = numArr.slice(0, dotIndex + digits + 1);

  // 核心处理逻辑
  if (parseInt(numArr[numArr.length - 1], 10) > 4) {
    // 如果最后一位大于4，则往前遍历+1
    for (let i = numArr.length - 2; i >= 0; i--) {
      numArr[i] = String(parseInt(numArr[i], 10) + 1);
      // 判断这位数字 +1 后会不会是 10
      if (numArr[i] === '10') {
        // 10的话处理一下变成 0，再次for循环，相当于给前面一个 +1
        numArr[i] = '0';
      } else {
        // 小于10的话，就打断循环，进位成功
        break;
      }
    }
  }
  // 将小数点加入数据
  numArr.splice(dotIndex, 0, '.');

  // 处理多余位数
  numArr.pop();

  // 如果事负数，添加负号
  if (isNegativeNum) {
    numArr.unshift('-');
  }

  return Number(numArr.join('')).toFixed(digits);
}

/**
 * 验证码校验
 * @param {*} val
 * @returns
 */
function passwordVerifiersFn(val) {
  let valArr = val.split('');
  let illegalStr = []; // 非法字符有哪些
  let verification1 = `ABCDEFGHIJKLMNOPQRSTUVWXYZ`;
  let verification2 = `abcdefghijklmnopqrstuvwxyz`;
  let verification3 = `0123456789`;
  let verification4 = `!@#$&*.`;
  let verificatType1 = []; // 大写字母收集
  let verificatType2 = []; // 小写字母收集
  let verificatType3 = []; // 数字类型收集
  let verificatType4 = []; // 特殊字母收集
  let verificationStr = verification1
    .concat(verification2)
    .concat(verification3)
    .concat(verification4);
  valArr.forEach((item) => {
    if (verificationStr.includes(item)) {
      if (verification1.includes(item)) {
        verificatType1.push(item);
      } else if (verification2.includes(item)) {
        verificatType2.push(item);
      } else if (verification3.includes(item)) {
        verificatType3.push(item);
      } else if (verification4.includes(item)) {
        verificatType4.push(item);
      }
    } else {
      illegalStr.push(item);
    }
  });

  let signArr = [];
  valArr.length < 8 && signArr.push('密码长度小于8位');
  valArr.length > 12 && signArr.push('密码长度大于12位');
  !verificatType1.length && signArr.push('未包含大写字母');
  !verificatType2.length && signArr.push('未包含小写字母');
  !verificatType3.length && signArr.push('未包含数字');
  !verificatType4.length && signArr.push('未包含特殊符号');
  illegalStr.length && signArr.push(`包含未指定字符：${signArr.join('')}`);

  if (signArr.length) {
    signArr.unshift('密码校验存在以下问题：');
    signArr.push('');
    signArr.push('温馨提示：');
    signArr.push('密码规则：8-12位，包含大小写字母、数字、特殊符号');
    signArr.push(`大写字母取值范围：${verification1}`);
    signArr.push(`小写字母取值范围：${verification2}`);
    signArr.push(`数字取值范围：${verification3}`);
    signArr.push(`特殊符号取值范围：${verification4}`);
    return signArr.join('\n');
  } else {
    return true;
  }
}

/* 设计到字符串隐藏类的函数 */

// 转换姓名
function HideStrPersonName(nameStr = '', character = '*') {
  try {
    if (CustomGetTypeOf(nameStr) !== 'string') {
      throw new Error('传入的姓名为非字符串');
    }

    if ([0, 1].includes(nameStr.length)) {
      return nameStr;
    } else if ([2].includes(nameStr.length)) {
      return nameStr.charAt(0) + character;
    } else {
      // 保留前一后一
      return nameStr.split('').reduce((prev, item, index) => {
        return (prev += [0, nameStr.length - 1].includes(index)
          ? item
          : character);
      }, '');
    }
  } catch (err) {
    console.log(err);
  }
}

// 转换地址:从城市后面都显示成X，只显示省市即可
function HideStrAddress(idNumber = '', type = 1) {}

/**
 * 判断一个数组是否是正序的二维数组
 * @param {*} arr
 * @returns {boolean}
 */
function IsAscendingOrderArr(arr = []) {
  if (!arr.length) return false;
  let flag = true;
  arr.forEach((item) => {
    let flag_01 = CustomGetTypeOf(item[0]) === 'number';
    let flag_02 = CustomGetTypeOf(item[1]) === 'number';
    let flag_03 = Number.isInteger(item[0]) && item[0] > -1;
    let flag_04 = Number.isInteger(item[1]) && item[1] > -1;
    let flag_05 = item[0] <= item[1];
    if (!(flag_01 && flag_02 && flag_03 && flag_04 && flag_05)) {
      flag = false;
    }
  });
  return flag;
}
/**
 * 判断是否一维数字数组
 * @param {array} arr
 * @returns {boolean}
 */
function OnedimensionalNumberArray(arr = []) {
  if (!arr.length) return false;
  let flag = true;
  arr.forEach((item) => {
    let flag_01 = CustomGetTypeOf(item) === 'number';
    let flag_02 = Number.isInteger(item); // 判断是否是整数
    let flag_03 = item > -1;
    if (!(flag_01 && flag_02 && flag_03)) {
      flag = false;
    }
  });
  return flag;
}

/**
 * 字符串处理的通用函数
 * @param {string} processStr -- 传入的字符串
 * @param {number,array} param_1
 * @param {nunber,string} param_2
 * @param {nunber} param_3
 * @returns {string}
 * 示例一：HideStrGeneral('abcdefghijklmn',[0,1,4,5,6],'x');// 动态替换索引位置的字符
 * 示例二：HideStrGeneral('abcdefghijklmn',1,5,'x');// 替换连续位置的字符
 * 示例三：HideStrGeneral('abcdefghijklmn',[[0,2],[4,6]],'x');// 替换分段索引位置的字符
 */
function HideStrGeneral(
  processStr = '',
  param_1, //[3,5]    [[1,3],[3,5],[6,8]]
  param_2 = '*',
  param_3 = '*'
) {
  try {
    if (CustomGetTypeOf(processStr) !== 'string') {
      throw new Error('请传入字符串');
    }
    if (!processStr.length) {
      return processStr;
    }

    if (CustomGetTypeOf(param_1) === 'array') {
      if (OnedimensionalNumberArray(param_1)) {
        // 纯一维数字数组
        return processStr.split('').reduce((prev, item, index) => {
          return (prev += param_1.includes(index) ? param_2 : item);
        }, '');
      } else if (IsAscendingOrderArr(param_1)) {
        // 纯二维数字数组
        param_1.forEach((item_01) => {
          processStr = processStr.split('').reduce((prev, item_02, index) => {
            return (prev +=
              item_01[0] <= index && index <= item_01[1] ? param_2 : item_02);
          }, '');
        });
        return processStr;
      } else {
        throw new Error('请检查数组格式');
      }
    } else if (CustomGetTypeOf(param_1) === 'number') {
      let flag_01 = Number.isInteger(param_1); // 判断是否是整数
      let flag_02 = Number.isInteger(param_2); // 判断是否是整数
      if (CustomGetTypeOf(param_2) === 'number' && flag_01 && flag_02) {
        if (param_1 > param_2) {
          throw new Error('字符串截取开始位置不能大于结束位置');
        }
        param_1 = param_1 > 0 ? param_1 : 0;
        param_2 = param_2 > processStr.length ? processStr.length : param_2;
        return processStr.split('').reduce((prev, item, index) => {
          return (prev +=
            param_1 <= index && index <= param_2 ? param_3 : item);
        }, '');
      } else {
        throw new Error('第二个参数、第三个参数需为非负整数');
      }
    } else {
      return processStr;
    }
  } catch (err) {
    console.log(err);
  }
}

/**
 * 获取类型(以全小写返回)
 * 2023年3月16日10:48:46
 * @param {*} obj
 * @returns
 * @since 1.0.17 郭坤 2023年3月16日10:51:25
 */
function CustomGetTypeOf(obj) {
  if (Number.isNaN(obj) && isNaN(obj)) return 'nan';
  return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
}

/**
 * 函数防抖：fn函数在最后一次调用时刻的delay毫秒之后执行！
 * @param fn 执行函数
 * @param delay 时间间隔
 * @param isImmediate 为true，debounce会在delay时间间隔的开始时立即调用这个函数
 * @returns {Function}
 * @since 1.0.17 郭坤 2023年3月16日11:18:21
 */
function CustomDebounce(fn, delay = 100, isImmediate = false) {
  var timer = null; // 初始化timer，作为计时清除依据
  return function () {
    var context = this; // 获取函数所在作用域this
    var args = arguments; // 取得传入参数
    clearTimeout(timer);
    if (isImmediate && timer === null) {
      fn.apply(context, args); // 时间间隔外立即执行
      timer = 0;
      return;
    }
    timer = setTimeout(function () {
      fn.apply(context, args);
      timer = null;
    }, delay);
  };
}

/**
 * 验证码校验
 * @param {*} val
 * @returns true/false
 */
const CustomPasswordVerifiersFn = (val) => passwordVerifiersFn(val);

/**
 * 姓名处理
 * @param {*} str
 * @param {*} type
 * @returns
 */
const CustomPersonNameFn = (str, params) =>
  HideStrPersonName(str, params);

const CustomHideStrGeneral = (...params) => HideStrGeneral(...params);
// export const CustomHideStrGeneral = (processStr, param_1, param_2, param_3) =>
//   HideStrGeneral(processStr, param_1, param_2, param_3);

export { CustomDateFtt, CustomDebounce, CustomGetTypeOf, CustomHideStrGeneral, CustomPasswordVerifiersFn, CustomPersonNameFn, HideStrAddress, HideStrGeneral, HideStrPersonName, NumberToFixed, numberFormat, passwordVerifiersFn };
